package com.yugao.fintech.antelope.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yugao.fintech.antelope.system.assembly.SysArticleAssembly;
import com.yugao.fintech.antelope.system.manager.SysArticleGroupManager;
import com.yugao.fintech.antelope.system.manager.SysArticleManager;
import com.yugao.fintech.antelope.system.mapper.SysArticleMapper;
import com.yugao.fintech.antelope.system.model.entity.SysArticle;
import com.yugao.fintech.antelope.system.model.entity.SysArticleGroup;
import com.yugao.fintech.antelope.system.model.rqrs.article.ArticlePageReq;
import com.yugao.fintech.antelope.system.model.rqrs.article.ArticleResp;
import com.yugao.fintech.antelope.system.model.rqrs.article.ArticleSaveReq;
import com.yugao.fintech.antelope.system.model.rqrs.article.ArticleUpdateReq;
import com.yugao.fintech.antelope.system.service.SysArticleService;
import com.yugao.fintech.framework.mybatisplus.utils.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 文章
 */
@Slf4j
@Service
public class SysArticleServiceImpl extends ServiceImpl<SysArticleMapper, SysArticle> implements IService<SysArticle>, SysArticleService {
    @Autowired
    private SysArticleManager articleManager;
    @Autowired
    private SysArticleGroupManager articleGroupManager;
    @Autowired
    private SysArticleAssembly articleAssembly;

    @Override
    public IPage<ArticleResp> pageArticle(ArticlePageReq req) {
        LocalDateTime beginTime = req.getBeginLocalDateTime();
        LocalDateTime endTime = req.getEndLocalDateTime();
        LambdaQueryWrapper<SysArticle> lqw = SysArticle.lqw()
                .eq(Objects.nonNull(req.getGroupId()), SysArticle::getGroupId, req.getGroupId())
                .ge(Objects.nonNull(beginTime), SysArticle::getCreatedAt, beginTime)
                .like(StringUtils.isNotEmpty(req.getTitle()), SysArticle::getTitle, req.getTitle())
                .le(Objects.nonNull(endTime), SysArticle::getCreatedAt, endTime)
                .orderByAsc(SysArticle::getSortNo)
                .orderByDesc(SysArticle::getCreatedAt);
        IPage<SysArticle> pageData = this.page(PageUtil.to(req), lqw);

        Set<Long> groupIds = pageData.getRecords().stream().map(SysArticle::getGroupId).filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // 避免为空查询报错
        groupIds.add(-1L);

        Map<Long, String> groupMap = articleGroupManager.listByIds(groupIds).stream()
                .collect(Collectors.toMap(SysArticleGroup::getId, SysArticleGroup::getName));

        // 将虚拟访问量和真实访问量相加
        pageData.getRecords().forEach(e -> e.setVisit(e.getVisit() + e.getVisitVirtual()));
        return PageUtil.to(pageData, (e) -> {
            ArticleResp resp = articleAssembly.toArticleResp(e);
            resp.setGroupName(groupMap.getOrDefault(e.getGroupId(), ""));
            return resp;
        });
    }

    @Override
    public ArticleResp getArticle(Long id) {
        SysArticle entity = this.getById(id);
        if (Objects.isNull(entity)) {
            return null;
        }
        // 将虚拟访问量和真实访问量相加
        entity.setVisit(entity.getVisit() + entity.getVisitVirtual());
        return articleAssembly.toArticleResp(entity);
    }

    @Override
    public boolean saveArticle(ArticleSaveReq req) {
        SysArticle entity = articleAssembly.toArticle(req);
        articleGroupManager.addArticleNum(entity.getGroupId());
        return this.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateArticle(ArticleUpdateReq req) {
        SysArticle newEntity = articleAssembly.toArticle(req);
        SysArticle oldEntity = this.getById(newEntity.getId());
        if (Objects.isNull(oldEntity)) {
            return false;
        }
        // 将原有的关联文章组的文章数量减1, 新关联的文章组的文章数加1
        articleGroupManager.decreaseArticleNum(oldEntity.getGroupId());
        articleGroupManager.addArticleNum(newEntity.getGroupId());
        return this.updateById(newEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteArticle(Long id) {
        SysArticle article = this.getById(id);
        if (Objects.isNull(article)) {
            return false;
        }
        articleGroupManager.decreaseArticleNum(article.getGroupId());
        return this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteArticle(List<Long> ids) {
        List<SysArticle> articles = this.listByIds(ids);
        List<Long> groupIds = articles.stream().map(SysArticle::getGroupId).filter(Objects::nonNull)
                .collect(Collectors.toList());
        articleGroupManager.batchDecreaseArticleNum(groupIds);
        return this.removeByIds(ids);
    }
}
